/**
 * Title:		KFrogFunction.java
 * Description: This class represents a function in KFrog. 
 * 
 * @version		1.0 May 2009
 * @author		Rami Habas
 */

package kfrog;

import kfrog.type.*;
import antlr.collections.AST;

public class KFrogFunction {

	/** function name */
	private String name;
	
	/** function signature */
	private String signature;
	
	/** formal or actual parameters */
	private KFrogDataType[] args;
	
	/** function body which is null for built-in functions */
	private AST body;
	
	/** function return data type */
	private KFrogDataType returnType;
	
	/** the static parent's symbol table */
	private KFrogSymbolTable staticParent;
	
	/** internal id used only for built-in functions */
	private int id;

	/**
     * Constructor used to instantiate a function with the given name,
     * parameters, body, return type, and parent's symbol table
     * 
     * @param name         Function name
     * @param args         Function arguments
     * @param body         Function body as an AST
     * @param returnType   Function's return type
     * @param staticParent Static parent's symbol table
     */
	KFrogFunction(String name, KFrogDataType[] args, AST body,
			KFrogDataType returnType,KFrogSymbolTable staticParent) {
		this.name = name;
		this.args = args;
		this.body = body;
		this.returnType = returnType;
		this.staticParent = staticParent;
		signature = getSignature(name, args);
	}

	/**
     * Constructor used to instantiate a built-in function with the given name,
     * parameters, and internal id.
     * 
     * @param name   Function name
     * @param args   Function arguments
     * @param id     Internal id
     */
	KFrogFunction(String name, KFrogDataType[] args, int id) {
		this.name = name;
		this.args = args;
		this.id = id;
		signature = getSignature(name, args);
	}

	public String getName() {
		return name;
	}

	public String getSignature() {
		return signature;
	}

	public KFrogDataType[] getArgs() {
		int argsLength = this.args.length;
		KFrogDataType[] args = new KFrogDataType[argsLength];

		for (int i = 0; i < argsLength; i++) {
			args[i] = this.args[i].newType();
			args[i].setName(this.args[i].getName());
		}

		return args;
	}

	public AST getBody() {
		return body;
	}

	public KFrogDataType getReturnType() {
		return returnType;
	}

	public KFrogSymbolTable getStaticParent() {
		return staticParent;
	}

	public int getId() {
		return id;
	}

	/** built-in functions have a null function body */
	public boolean isBuiltIn() {
		return body == null;
	}

	public boolean isReturnTypeVoid() {
		return (returnType instanceof KFrogVoid);
	}

	/** converting to String is useful for debugging purposes */
	public String toString() {
		int argsLength = args.length;
		StringBuffer strBuf = new StringBuffer(returnType.typeName());

		strBuf.append(" " + name + "(");

		for (int i = 0; i < argsLength; i++){

			strBuf.append(args[i].typeName() + " " + args[i].getName());

			if (i < argsLength - 1)
				strBuf.append(", ");
		}
		strBuf.append(")");

		return strBuf.toString();
	}

	/**
     * Helper method that returns a function signature given the function name
     * and parameters.
     * 
     * @param name   Function name
     * @param args   Function arguments
     */
	public static String getSignature(String name, KFrogDataType[] args) {

		if (args == null)
			return name + "()";

		int argsLength = args.length;
		StringBuffer signatureBuf = new StringBuffer(name + "(");

		for (int i = 0; i < argsLength; i++) {

			if (!(args[i] instanceof KFrogDataType))
				throw new RuntimeException("Illegal type in function signature "
						+ args[i] + " function " + name + "()");

			signatureBuf.append(args[i].typeName());

			if (i < argsLength - 1)
				signatureBuf.append(",");
		}
		signatureBuf.append(")");

		return signatureBuf.toString();
	}
}
